狀態模式使用狀態物件來表示物件在不同狀態下的行為,並通過改變狀態物件來改變行為。
街道中的紅綠燈非常適合用來說明狀態模式的概念。紅綠燈有三種狀態:紅燈、黃燈和綠燈,分別代表禁止通行、減速慢行和自由通行。這些狀態擁有不同的呈現方式與提示作用,儘管紅綠燈不會隨著狀態的變化而改變自身行為,用路人卻會隨著不同的狀態而改變行為,這與狀態模式中一種狀態對應一種行為的精神十分相似。
在前端的世界裡,狀態模式無所不在。我們透過改變狀態來改變元件的外觀、行為,甚至是事件的反應,可以說狀態是我們最好的朋友也不為過。不過,狀態模式並不屬於前端的專利,任何帶有狀態的物件都能藉由它來管理行為。讓我們看看如何使用狀態模式來管理音樂播放器的播放與暫停狀態。
PlayerState
是播放器狀態的介面,包含一個 handle
方法,讓具體狀態來定義如何處理播放器的狀態轉換。
interface PlayerState {
handle(player: MusicPlayer): void;
}
定義具體的播放器狀態。播放器會執行當前狀態的 handle
方法,將狀態切換成播放或停止。
class PlayingState implements PlayerState {
handle(player: MusicPlayer) {
player.setState(new PausedState());
console.log("Music is now Paused.");
}
}
class PausedState implements PlayerState {
handle(player: MusicPlayer) {
player.setState(new PlayingState());
console.log("Music is now Playing.");
}
}
MusicPlayer
是音樂播放器,currentState
屬性代表播放器的播放狀態。
class MusicPlayer {
private currentState: PlayerState;
constructor() {
this.currentState = new PausedState();
}
setState(state: PlayerState) {
this.currentState = state;
}
pressPlayPause() {
this.currentState.handle(this);
}
}
建立一個音樂播放器,然後重複呼叫 pressPlayPause()
來觀察播放器狀態在播放與暫停之間的切換。
class MusicPlayerTestDrive {
static main() {
const player = new MusicPlayer();
player.pressPlayPause();
player.pressPlayPause();
player.pressPlayPause();
}
}
MusicPlayerTestDrive.main();
狀態模式包含三種角色:
狀態模式透過狀態物件來管理物件在不同狀態下的行為。每個狀態物件代表一種特定的狀態與其對應的行為模式。當物件的狀態改變時,只需更換對應的狀態物件,物件的行為就會隨之改變。我們不需要透過條件判斷式來改變程式的行為,這讓程式變得更容易閱讀。同時,我們可以透過新增或修改狀態物件來改變物件的行為,無需修改原有的程式邏輯,使得程式更容易擴充與維護。